#include "memalloc.hpp"


SmartPtrImpl::SmartPtrImpl() {
	count = 0;
	get_count = 0;
	state = INVALID;
}


SmartPtrImpl::SmartPtrImpl(char* pValue){
	pData = pValue;
	count = 0;
	get_count = 0;
	state = INVALID;
}


SmartPtrImpl::~SmartPtrImpl(){
	MemAllocImpl::Free(this, 1);
}


char* SmartPtrImpl::Pointer(bool get = false) {
	if (state == INVALID){
		throw;// Pointer is invalid!!!
	}
        else if (state == UNINITED){
            uint64_t chunk_num = MemAllocImpl::inst->free_swap_chunks[sz_num].Pop();
            if (chunk_num == -1){
		int i = sz_num;
		while (i < MemAllocImpl::inst->N_swap && chunk_num == -1){
			i++;
			chunk_num = MemAllocImpl::inst->free_swap_chunks[i].Pop();
		}
		if (chunk_num != -1){
			//go back down, splitting chunks
			while (i > sz_num){
				List<uint64_t>::Merge(MemAllocImpl::inst->free_swap_chunks, i - 1, MemAllocImpl::inst->N_swap, chunk_num);
				chunk_num = BUDDY(chunk_num, i - 1);
				i--;
			}
		}
		else{
			throw MemAllocException(MemAllocException::E_2BIG, "Fragmentaion of swap!");
		}
            }
            MemAllocImpl::inst->count_page_swap[chunk_num * MemAllocImpl::min_chunk / MemAllocImpl::PAGESIZE].alloc_count += 1;
            offset = chunk_num;
        }
        uint64_t swap_page_num = offset * MemAllocImpl::inst->min_chunk / MemAllocImpl::PAGESIZE;
	try {
		if (MemAllocImpl::inst->SwapToMem(this) == 0){
			throw;
		}
		if (get){
			if (get_count++ == 0){
				MemAllocImpl::inst->mem_free -= size;
				MemAllocImpl::inst->count_page_swap[swap_page_num].get_count += 1;
			}
		}
	}
	catch (MemAllocException& e){
		throw e;
	}
	catch (...){
	}
	char* ret = pData;
	return ret;
}


void SmartPtrImpl::Release() {
	uint64_t swap_page_num = offset * MemAllocImpl::inst->min_chunk / MemAllocImpl::PAGESIZE;
	if (get_count > 0){
                get_count--;
		//then it must be in memory
		if (!get_count){
			MemAllocImpl::inst->mem_free += size;
			//MemAllocImpl::inst->count_page_swap[swap_page_num].get_count -= 1;
			if (!(MemAllocImpl::inst->count_page_swap[swap_page_num].get_count -= 1)){
				MemAllocImpl::inst->released_mem_pages[page_size_num].Push(swap_page_num);
			}
		}
		return;
	}
	else{
		throw MemAllocException(MemAllocException::E_2BIG, "Release without get!");//!!! need to add exception
	}
}


void SmartPtrImpl::RefDec(){
	if (count-- == 1){
		delete this;
	}
}


void SmartPtrImpl::RefInc(){
	count++;
}


void* SmartPtrImpl::operator new(size_t size){
        return Garbage<SmartPtrImpl>::Pop();
}

void SmartPtrImpl::operator delete(void* it){
       Garbage<SmartPtrImpl>::Push( (SmartPtrImpl*) it );
}


